package com.dbms;

import com.dbms.common.Column;
import com.dbms.common.QueryResult;
import com.dbms.common.Tuple;
import com.dbms.DbmsCore;
import java.io.File;

/**
 * 一个专门用于演示DBMS用户及权限管理功能的独立测试程序。
         * 本程序将展示以下核心安全功能：
         * 1.  用户管理：创建和删除用户。
         * 2.  权限管理：授予（GRANT）和回收（REVOKE）用户对特定表的权限。
         * 3.  权限验证：验证用户只能执行其被授予的操作。
         *
         * 【已修正】确保测试使用独立的文件。
         */
public class SecurityTest {
    // 为本次测试指定独立的数据库和日志文件名
    private static final String DB_FILE_NAME = "security_test.db";
    private static final String LOG_FILE_NAME = "security_test.log";

    public static void main(String[] args) throws InterruptedException {
        System.out.println("============== 用户及权限管理功能演示开始 ==============\n");

        // --- 准备阶段 ---
        System.out.println("--- 准备阶段：清理环境并创建初始数据 ---");
        new File(DB_FILE_NAME).delete();
        new File(LOG_FILE_NAME).delete();

        // 【核心修正】创建两个DbmsCore实例，但它们共享同一个底层的数据库文件。
        // 一个模拟管理员（默认用户，拥有所有权限），另一个将用于模拟普通用户。
        final DbmsCore dbmsAsAdmin = new DbmsCore(DB_FILE_NAME, LOG_FILE_NAME);
        final DbmsCore dbmsAsUser = new DbmsCore(DB_FILE_NAME, LOG_FILE_NAME);

        dbmsAsAdmin.processSql("CREATE TABLE products (id INT PRIMARY KEY, name VARCHAR(50));");
        dbmsAsAdmin.processSql("INSERT INTO products VALUES (1, 'Laptop');");
        System.out.println("初始数据 'products' 表已创建。\n");

        // --- 第一幕：用户管理 ---
        demonstrateUserManagement(dbmsAsAdmin);

        System.out.println("\n\n============== 用户管理演示结束 ==============");
        System.out.println("=========== 即将开始权限管理演示 ===========\n\n");
        Thread.sleep(2000);

        // --- 第二幕：权限管理 ---
        demonstratePermissionManagement(dbmsAsAdmin, dbmsAsUser);

        System.out.println("\n============== 演示结束 ==============");
        dbmsAsAdmin.shutdown();
    }

    /**
     * 演示创建和删除用户。所有操作都由管理员执行。
     */
    private static void demonstrateUserManagement(DbmsCore dbmsAsAdmin) {
        System.out.println("--- Part 1: 用户生命周期管理 (CREATE & DROP USER) ---");
        System.out.println("--------------------------------------------------\n");

        // 1. 创建用户
        System.out.println("--- 1. [Admin] 创建一个新用户 'sales_user' ---");
        printResult(dbmsAsAdmin.processSql("CREATE USER sales_user IDENTIFIED BY 'password123';"));

        // 2. 验证用户创建成功
        System.out.println("\n--- 2. [Admin] 查询系统表 `_users_` 验证用户是否存在 ---");
        printResult(dbmsAsAdmin.processSql("SELECT user_name FROM _users_;"));

        // 3. 删除用户
        System.out.println("\n--- 3. [Admin] 删除用户 'sales_user' ---");
        printResult(dbmsAsAdmin.processSql("DROP USER sales_user;"));

        // 4. 验证用户已被删除
        System.out.println("\n--- 4. [Admin] 再次查询 `_users_` 验证用户已被删除 ---");
        printResult(dbmsAsAdmin.processSql("SELECT user_name FROM _users_;"));
        System.out.println("✅ 结论：CREATE USER 和 DROP USER 功能正常。");
    }

    /**
     * 演示授权、验证权限、回收权限的全过程。
     */
    private static void demonstratePermissionManagement(DbmsCore dbmsAsAdmin, DbmsCore dbmsAsUser) {
        System.out.println("--- Part 2: 权限授予与回收 (GRANT & REVOKE) ---");
        System.out.println("--------------------------------------------------\n");

        // 1. 准备用户
        System.out.println("--- 1. [Admin] 为演示重新创建用户 'sales_user' ---");
        dbmsAsAdmin.processSql("CREATE USER sales_user IDENTIFIED BY 'password123';");
        System.out.println("用户 'sales_user' 已创建。\n");

        // 2. 尝试用新用户登录并访问
        System.out.println("--- 2. [sales_user] 尝试登录并查询 'products' 表 (预期：失败) ---");
        boolean loginSuccess = dbmsAsUser.authenticate("sales_user", "password123");
        if(loginSuccess) {
            System.out.println("用户 'sales_user' 登录成功。");
            printResult(dbmsAsUser.processSql("SELECT * FROM products;"));
        } else {
            System.out.println("登录失败！");
        }
        System.out.println("✅ 结论：新创建的用户默认没有任何权限，访问被拒绝。\n");

        // 3. 授予 SELECT 权限
        System.out.println("--- 3. [Admin] 授予 'sales_user' 对 'products' 表的 SELECT 权限 ---");
        printResult(dbmsAsAdmin.processSql("GRANT SELECT ON products TO sales_user;"));
        System.out.println("\n--- [Admin] 查看 `_privileges_` 表确认授权 ---");
        printResult(dbmsAsAdmin.processSql("SELECT * FROM _privileges_;"));

        // 4. 再次尝试访问
        System.out.println("\n--- 4. [sales_user] 获得授权后，再次查询 'products' 表 (预期：成功) ---");
        printResult(dbmsAsUser.processSql("SELECT * FROM products;"));
        System.out.println("✅ 结论：GRANT 授权成功，用户现在可以查询数据。\n");

        // 5. 验证权限边界
        System.out.println("--- 5. [sales_user] 尝试 INSERT 数据到 'products' 表 (预期：失败) ---");
        printResult(dbmsAsUser.processSql("INSERT INTO products VALUES (2, 'Mouse');"));
        System.out.println("✅ 结论：权限控制是精确的，用户不能执行未被授予的操作。\n");

        // 6. 回收权限
        System.out.println("--- 6. [Admin] 收回 'sales_user' 的 SELECT 权限 ---");
        printResult(dbmsAsAdmin.processSql("REVOKE SELECT ON products FROM sales_user;"));
        System.out.println("\n--- [Admin] 查看 `_privileges_` 表确认权限已被回收 ---");
        printResult(dbmsAsAdmin.processSql("SELECT * FROM _privileges_;"));

        // 7. 最后一次验证
        System.out.println("\n--- 7. [sales_user] 权限被回收后，再次查询 'products' 表 (预期：失败) ---");
        printResult(dbmsAsUser.processSql("SELECT * FROM products;"));
        System.out.println("✅ 结论：REVOKE 成功收回了用户的权限。");
    }

    /**
     * 一个简单的辅助方法，用于将查询结果打印到控制台。
     */
    private static void printResult(QueryResult result) {
        if (result == null) return;
        if (result.isSuccess) {
            if (result.schema != null && !result.tuples.isEmpty()) {
                for (Column col : result.schema.getColumns()) {
                    System.out.print(col.getColumnName() + "\t | ");
                }
                System.out.println("\n-------------------------------------");
                for (Tuple tuple : result.tuples) {
                    System.out.println(tuple.toString());
                }
            }
            if (result.message != null && result.tuples.isEmpty()) {
                System.out.println(result.message);
            }
        } else {
            System.err.println(result.message);
        }
    }
}